#include <jni.h>
#include <android/native_window_jni.h>
#include <unordered_map>
#include <mutex>
#include <stdexcept>
#include "../player/av_player_core.h"
#include "../player/av_player_common.h"
#include "utils_log.h"

#define LOG_TAG "AVPlayerJNI"

// 全局JVM引用（生命周期与进程一致）
static JavaVM* g_jvm = nullptr;

// 映射表：保存Native核心实例与Java回调对象的关联（线程安全）
static std::unordered_map<AVPlayerCore*, jobject> g_core_map;
static std::mutex g_map_mutex;

// 线程局部存储：当前回调上下文的播放器实例（避免多线程干扰）
static thread_local AVPlayerCore* tls_core = nullptr;

/**
 * 获取当前线程的JNI环境
 * @param is_attached [输出] 是否为新附着的线程
 * @return JNIEnv指针（可能为null）
 */
static JNIEnv* get_jni_env(bool* is_attached) {
    *is_attached = false;
    JNIEnv* env = nullptr;
    jint ret = g_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);

    // 如果线程未附着，尝试附着到JVM
    if (ret == JNI_EDETACHED) {
        if (g_jvm->AttachCurrentThread(&env, nullptr) == JNI_OK) {
            *is_attached = true;
        } else {
            LOGE(LOG_TAG, "Failed to attach thread to JVM");
        }
    } else if (ret != JNI_OK) {
        LOGE(LOG_TAG, "Failed to get JNI env, error: ", ret);
    }
    return env;
}

/**
 * 释放JNI环境（如果是临时附着的线程）
 * @param is_attached 是否为附着的线程
 */
static void release_jni_env(bool is_attached) {
    if (is_attached && g_jvm) {
        g_jvm->DetachCurrentThread();
    }
}

/**
 * 将Native状态回调转发到Java层
 * @param state 播放器状态
 */
static void native_state_callback(MediaState state) {
    if (!tls_core) {
        LOGE(LOG_TAG, "state callback failed: tls_core is null");
        return;
    }

    // 查找对应的Java对象（加锁保护）
    jobject java_obj = nullptr;
    {
        std::lock_guard<std::mutex> lock(g_map_mutex);
        auto it = g_core_map.find(tls_core);
        if (it != g_core_map.end()) {
            java_obj = it->second; // 全局引用，无需额外释放
        }
    }

    if (!java_obj) {
        LOGE(LOG_TAG, "state callback failed: java object not found for core");
        return;
    }

    // 调用Java层的onStateChanged方法
    bool is_attached = false;
    JNIEnv* env = get_jni_env(&is_attached);
    if (env) {
        jclass cls = env->GetObjectClass(java_obj);
        if (cls) {
            jmethodID mid = env->GetMethodID(cls, "onStateChanged", "(I)V");
            if (mid) {
                // 传递状态的Native编码（与Java层PlayerState枚举对应）
                env->CallVoidMethod(java_obj, mid, static_cast<jint>(state));
            } else {
                LOGE(LOG_TAG, "onStateChanged method not found in Java class");
            }
            env->DeleteLocalRef(cls); // 释放局部引用
        } else {
            LOGE(LOG_TAG, "failed to get Java class for callback");
        }
    }
    release_jni_env(is_attached);
}

/**
 * Native层状态回调入口（由AVPlayerCore调用）
 * @param state 播放器状态
 * @param core 当前播放器核心实例（由AVPlayerCore传递this指针）
 */
static void state_callback_func(MediaState state, AVPlayerCore* core) {
    if (!core) {
        LOGE(LOG_TAG, "state_callback_func: invalid core instance (null)");
        return;
    }

    // 通过TLS传递实例到转发函数，避免多线程冲突
    tls_core = core;
    native_state_callback(state);
    tls_core = nullptr; // 清除TLS，避免线程复用导致的问题
}

/**
 * JNI加载时初始化（获取JVM引用）
 */
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    g_jvm = vm; // 保存JVM引用（全局有效）
    return JNI_VERSION_1_6;
}

/**
 * JNI卸载时清理资源
 */
void JNI_OnUnload(JavaVM* vm, void* reserved) {
    std::lock_guard<std::mutex> lock(g_map_mutex);
    JNIEnv* env = nullptr;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) == JNI_OK) {
        // 释放所有Java全局引用
        for (auto& pair : g_core_map) {
            env->DeleteGlobalRef(pair.second);
        }
    }
    g_core_map.clear();
    g_jvm = nullptr; // 清除JVM引用
}

/**
 * 创建Native播放器实例
 */
extern "C" JNIEXPORT jlong JNICALL
Java_com_example_mediacore_player_NativePlayer_nativeCreate(JNIEnv* env, jobject thiz) {
    try {
        AVPlayerCore* core = new AVPlayerCore();
        LOGD(LOG_TAG, "Created new AVPlayerCore instance");
        return reinterpret_cast<jlong>(core);
    } catch (const std::exception& e) {
        LOGE(LOG_TAG, "nativeCreate failed: ", e.what());
    } catch (...) {
        LOGE(LOG_TAG, "nativeCreate failed with unknown exception");
    }
    return 0;
}

/**
 * 初始化播放器（设置播放地址、渲染窗口等）
 */
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediacore_player_NativePlayer_nativeInit(
        JNIEnv* env, jobject thiz, jlong ptr, jstring url, jobject surface) {
    if (!ptr) {
        LOGE(LOG_TAG, "nativeInit failed: invalid core pointer (null)");
        return;
    }
    AVPlayerCore* core = reinterpret_cast<AVPlayerCore*>(ptr);

    // 清理旧的Java引用（避免内存泄漏）
    {
        std::lock_guard<std::mutex> lock(g_map_mutex);
        auto it = g_core_map.find(core);
        if (it != g_core_map.end()) {
            env->DeleteGlobalRef(it->second);
            g_core_map.erase(it);
            LOGD(LOG_TAG, "Cleared old Java reference for core ");
        }
    }

    // 创建新的Java全局引用（关联Native实例与Java回调对象）
    jobject global_ref = env->NewGlobalRef(thiz);
    if (!global_ref) {
        LOGE(LOG_TAG, "nativeInit failed: cannot create global reference");
        return;
    }
    {
        std::lock_guard<std::mutex> lock(g_map_mutex);
        g_core_map[core] = global_ref;
        LOGD(LOG_TAG, "Associated core with Java object ");
    }

    // 设置状态回调函数（直接绑定，无需全局临时变量）
    core->setStatusCallback(state_callback_func);

    // 转换播放地址（JString -> C++ string）
    const char* c_url = env->GetStringUTFChars(url, nullptr);
    if (!c_url) {
        LOGE(LOG_TAG, "nativeInit failed: invalid url string");
        return;
    }
    std::string media_url(c_url);
    env->ReleaseStringUTFChars(url, c_url); // 立即释放临时字符

    // 转换渲染窗口（Surface -> ANativeWindow）
    ANativeWindow* window = nullptr;
    if (surface) {
        window = ANativeWindow_fromSurface(env, surface);
        if (!window) {
            LOGE(LOG_TAG, "nativeInit failed: cannot get ANativeWindow from Surface");
            return;
        }
    }

    // 初始化播放器核心
    try {
        core->initialize(media_url, window);
        LOGD(LOG_TAG, "Core initialized with url: ", media_url.c_str());
    } catch (const std::exception& e) {
        LOGE(LOG_TAG, "initialize failed: ", e.what());
        if (window) ANativeWindow_release(window);
        env->DeleteGlobalRef(global_ref);
        g_core_map.erase(core);
    } catch (...) {
        LOGE(LOG_TAG, "initialize failed with unknown exception");
        if (window) ANativeWindow_release(window);
        env->DeleteGlobalRef(global_ref);
        g_core_map.erase(core);
    }
}

/**
 * 开始播放
 */
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediacore_player_NativePlayer_nativeStart(JNIEnv* env, jobject thiz, jlong ptr) {
    if (!ptr) return;
    AVPlayerCore* core = reinterpret_cast<AVPlayerCore*>(ptr);
    try {
        core->startPlayback();
        LOGD(LOG_TAG, "Core start playback");
    } catch (const std::exception& e) {
        LOGE(LOG_TAG, "nativeStart failed: ", e.what());
    } catch (...) {
        LOGE(LOG_TAG, "nativeStart failed with unknown exception");
    }
}

/**
 * 暂停播放
 */
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediacore_player_NativePlayer_nativePause(JNIEnv* env, jobject thiz, jlong ptr) {
    if (!ptr) return;
    AVPlayerCore* core = reinterpret_cast<AVPlayerCore*>(ptr);
    try {
        core->pausePlayback();
        LOGD(LOG_TAG, "Core paused");
    } catch (const std::exception& e) {
        LOGE(LOG_TAG, "nativePause failed: ", e.what());
    } catch (...) {
        LOGE(LOG_TAG, "nativePause failed with unknown exception");
    }
}

/**
 * 停止播放
 */
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediacore_player_NativePlayer_nativeStop(JNIEnv* env, jobject thiz, jlong ptr) {
    if (!ptr) return;
    AVPlayerCore* core = reinterpret_cast<AVPlayerCore*>(ptr);
    try {
        core->stopPlayback();
        LOGD(LOG_TAG, "Core stopped");
    } catch (const std::exception& e) {
        LOGE(LOG_TAG, "nativeStop failed: ", e.what());
    } catch (...) {
        LOGE(LOG_TAG, "nativeStop failed with unknown exception");
    }
}

/**
 * 跳转到指定位置（微秒）
 */
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediacore_player_NativePlayer_nativeSeek(JNIEnv* env, jobject thiz, jlong ptr, jlong us) {
    if (!ptr) return;
    AVPlayerCore* core = reinterpret_cast<AVPlayerCore*>(ptr);
    try {
        core->seekTo(static_cast<int64_t>(us));
        LOGD(LOG_TAG, "Core seek to ", us, " us");
    } catch (const std::exception& e) {
        LOGE(LOG_TAG, "nativeSeek failed: ", e.what());
    } catch (...) {
        LOGE(LOG_TAG, "nativeSeek failed with unknown exception");
    }
}

/**
 * 获取当前播放位置（微秒）
 */
extern "C" JNIEXPORT jlong JNICALL
Java_com_example_mediacore_player_NativePlayer_nativeGetPosition(JNIEnv* env, jobject thiz, jlong ptr) {
    if (!ptr) return -1;
    AVPlayerCore* core = reinterpret_cast<AVPlayerCore*>(ptr);
    try {
        int64_t pos = core->getCurrentPosition();
        LOGD(LOG_TAG, "Core current position: ", pos, " us");
        return static_cast<jlong>(pos);
    } catch (const std::exception& e) {
        LOGE(LOG_TAG, "nativeGetPosition failed: ", e.what());
    } catch (...) {
        LOGE(LOG_TAG, "nativeGetPosition failed with unknown exception");
    }
    return -1;
}

/**
 * 获取当前播放状态（Native编码）
 */
extern "C" JNIEXPORT jint JNICALL
Java_com_example_mediacore_player_NativePlayer_nativeGetState(JNIEnv* env, jobject thiz, jlong ptr) {
    if (!ptr) return -1;
    AVPlayerCore* core = reinterpret_cast<AVPlayerCore*>(ptr);
    try {
        MediaState state = core->getState();
        LOGD(LOG_TAG, "Core current state: ", static_cast<int>(state));
        return static_cast<jint>(state);
    } catch (const std::exception& e) {
        LOGE(LOG_TAG, "nativeGetState failed: ", e.what());
    } catch (...) {
        LOGE(LOG_TAG, "nativeGetState failed with unknown exception");
    }
    return -1;
}

/**
 * 释放播放器资源
 */
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediacore_player_NativePlayer_nativeRelease(JNIEnv* env, jobject thiz, jlong ptr) {
    if (!ptr) return;
    AVPlayerCore* core = reinterpret_cast<AVPlayerCore*>(ptr);
    LOGD(LOG_TAG, "Releasing core");

    // 清理Java引用映射
    {
        std::lock_guard<std::mutex> lock(g_map_mutex);
        auto it = g_core_map.find(core);
        if (it != g_core_map.end()) {
            env->DeleteGlobalRef(it->second);
            g_core_map.erase(it);
            LOGD(LOG_TAG, "Released Java reference for core");
        }
    }

    // 释放Native实例
    delete core;
}